package com.jphenix.share.tools;

import com.jphenix.standard.docs.ClassInfo;

import javax.imageio.IIOImage;
import javax.imageio.ImageIO;
import javax.imageio.ImageWriteParam;
import javax.imageio.ImageWriter;
import javax.imageio.stream.ImageOutputStream;
import javax.swing.*;
import javax.swing.text.Document;
import javax.swing.text.Element;
import javax.swing.text.View;
import javax.swing.text.ViewFactory;
import javax.swing.text.html.HTMLDocument;
import javax.swing.text.html.HTMLEditorKit;
import javax.swing.text.html.ImageView;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.Iterator;

/**
 * HTML转图片
 * @author MBG
 * 2018年9月12日
 */
@ClassInfo({"2018-09-12 10:43","HTML转图片"})
public class Html2Jpg {

	private JEditorPane editorPane; //页面面板
	private final static Dimension DEFAULT_SIZE = new Dimension(800, 800); //默认页面尺寸对象

	/**
	 * HTML解析类
	 * @author MBG
	 */
	public class SynchronousHTMLEditorKit extends HTMLEditorKit {

		/**
	     * 串行标识
	     */
	    private static final long serialVersionUID = -3857336842162142645L;

	    /**
	     * 构造函数
	     */
	    @Override
        public Document createDefaultDocument() {
			HTMLDocument doc = (HTMLDocument) super.createDefaultDocument();
			doc.setAsynchronousLoadPriority(-1);
			return doc;
		}

	    /**
	     * 获取视图工厂类
	     */
		@Override
        public ViewFactory getViewFactory() {
			return new HTMLFactory() {
				@Override
                public View create(Element elem) {
					View view = super.create(elem);
					if (view instanceof ImageView) {
						((ImageView) view).setLoadsSynchronously(true);
					}
					return view;
				}
			};
		}
	}
	
	/**
	 * 构造函数
	 */
	public Html2Jpg() {
		editorPane = createJEditorPane();
	}
	
	/**
	 * 执行转换
	 * @param url            页面URL
	 * @param savePath       保存路径
	 * @throws Exception     异常
	 */
	public static void build(String url,String savePath) throws Exception {
		Html2Jpg hj = new Html2Jpg();
		hj.loadUrl(url);
		hj.saveAsImage(savePath);
	}
	
	/**
	 * 获取页面尺寸信息类对象
	 * @return 页面尺寸信息类对象
	 */
	public Dimension getSize() {
		return editorPane.getSize();
	}

	/**
	 * 加载指定页面路径
	 * @param url 指定页面路径
	 * @throws Exception 异常
	 */
	public void loadUrl(URL url) throws Exception {
		try {
			editorPane.setPage(url);
		} catch (Exception e) {
			throw new Exception(String.format("Exception while loading %s", url), e);
		}
	}

	/**
	 * 加载指定页面路径
	 * @param url 指定页面路径
	 * @throws Exception 异常
	 */
	public void loadUrl(String url) throws Exception {
		try {
			editorPane.setPage(url);
		} catch (Exception e) {
			throw new Exception(String.format("Exception while loading %s", url), e);
		}
	}

	/**
	 * 加载指定页面内容
	 * @param html 指定页面内容
	 */
	public void loadHtml(String html) {
		editorPane.setText(html);
	}


	/**
	 * 保存图片
	 * @param file 图片文件绝对路径
	 */
	public void saveAsImage(String file) {
		saveAsImage(new File(file));
	}

	/**
	 * 保存图片
	 * @param file 图片文件对象
	 */
	public void saveAsImage(File file) {
		//设置缓存路径
		if(ImageIO.getCacheDirectory()==null) {
			ImageIO.setUseCache(true);
			ImageIO.setCacheDirectory(new File(System.getProperty("java.io.tmpdir")));
		}
		BufferedImage img = getBufferedImage();
		try {
			final String formatName = formatForFilename(file.getName());
			ImageIO.write(img, formatName, file);
		} catch (IOException e) {
			throw new RuntimeException(String.format("Exception while saving '%s' image", file), e);
		}
		try {
			img.getGraphics().dispose();
		}catch(Exception e) {}
	}

	/**
	 * 另存图片
	 * @param filePath 图片对象
	 * @param quality 图片质量
	 */
	public void saveAsImage(String filePath,float quality) {
		saveAsImage(new File(filePath),quality);
	}

	/**
	 * 另存图片
	 * @param file 图片对象
	 * @param quality 图片质量
	 */
	public void saveAsImage(File file,float quality) {
		BufferedImage img = getBufferedImage();
		ImageOutputStream outputStream = null; //图片输出留
		ImageWriter writer = null;
		//设置缓存路径
		if(ImageIO.getCacheDirectory()==null) {
			ImageIO.setUseCache(true);
			ImageIO.setCacheDirectory(new File(System.getProperty("java.io.tmpdir")));
		}
		try {
			// 得到指定Format图片的writer  
			Iterator<ImageWriter> iter = ImageIO.getImageWritersByFormatName("jpeg");// 得到迭代器  
			writer = iter.next(); // 得到writer

			// 得到指定writer的输出参数设置(ImageWriteParam )  
			ImageWriteParam iwp = writer.getDefaultWriteParam();  
			iwp.setCompressionMode(ImageWriteParam.MODE_EXPLICIT); // 设置可否压缩  
			iwp.setCompressionQuality(quality); // 设置压缩质量参数  
			iwp.setProgressiveMode(ImageWriteParam.MODE_DISABLED);  

			ColorModel colorModel = ColorModel.getRGBdefault();  
			// 指定压缩时使用的色彩模式  
			iwp.setDestinationType(new javax.imageio.ImageTypeSpecifier(colorModel,  
					colorModel.createCompatibleSampleModel(16, 16)));  
			outputStream = ImageIO.createImageOutputStream(file);
			writer.setOutput(outputStream);
			writer.write(null, new IIOImage(img, null, null), iwp);
		} catch (IOException e) {
			throw new RuntimeException(String.format("Exception while saving '%s' image", file), e);
		}finally {
			try {
				//允许释放此对象保存的所有资源。
				writer.dispose();
			}catch(Exception e) {}
			try {
				outputStream.close();
			}catch(Exception e2) {}
		}
	}

	/**
	 * 返回默认页面尺寸对象
	 * @return 默认页面尺寸对象
	 */
	public Dimension getDefaultSize() {
		return DEFAULT_SIZE;
	}

	/**
	 * 返回图片缓存对象
	 * @return 图片缓存对象
	 */
	public BufferedImage getBufferedImage() {
		Dimension prefSize = editorPane.getPreferredSize();
		BufferedImage img = new BufferedImage(prefSize.width, editorPane.getPreferredSize().height, BufferedImage.TYPE_3BYTE_BGR);
		Graphics graphics = img.getGraphics();
		editorPane.setSize(prefSize);
		editorPane.paint(graphics);
		return img;
	}

	
	/**
	 * 创建页面面板对象
	 * @return 页面面板对象
	 */
	protected JEditorPane createJEditorPane() {
		final JEditorPane editorPane = new JEditorPane();
		editorPane.setSize(getDefaultSize());
		editorPane.setEditable(false);
		final SynchronousHTMLEditorKit kit = new SynchronousHTMLEditorKit();
		editorPane.setEditorKitForContentType("text/html", kit);
		editorPane.setContentType("text/html");
		return editorPane;
	}
	
	/**
	 * 通过文件扩展名判断文件类型
	 * @param ext 文件扩展名
	 * @return 文件类型
	 */
	private String formatForExtension(String ext) {
		if(ext==null || ext.length()<1) {
			return "png";
		}
		if("jpg".equals(ext) || "jpeg".equals(ext)) {
			return "jpg";
		}
		if("gif".equals(ext)) {
			return "gif";
		}
		return "png";
	}

	/**
	 * 通过文件名返回文件类型
	 * @param fileName 文件名
	 * @return 文件类型
	 */
	private String formatForFilename(String fileName) {
		int dotIndex = fileName.lastIndexOf('.');
		if (dotIndex < 0) {
			return "png";
		}
		return formatForExtension(fileName.substring(dotIndex + 1));
	}
}
